package com.alex.ui;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.FocusFinder;
import android.view.KeyEvent;
import android.view.View;
import android.widget.AbsoluteLayout.LayoutParams;

import com.alex.ui.ass.GridViewAttr;
import com.alex.ui.ass.IAdapter;
import com.alex.ui.ass.ViewWithShadowAttr;
import com.helios.baseFunction.Define.KeyCode;
import com.helios.protocol.Anim;
import com.helios.ui.IView;
import com.helios.ui.Util;

@SuppressLint("NewApi")
@SuppressWarnings({ "unused", "deprecation" })
public class MGridView extends MGroupView {
	
	private GridViewAttr mAttrGroup;
	private ViewWithShadowAttr mAttrItem;
	
	private int mContentHeight;
	
	protected int mContentOffsetY;
	
	private int mTargetFocus = INVALIDATE_INDEX;
	
	private long lastTime;

	public MGridView(Context context) {
		super(context);
		
		init();
	}

	public MGridView(Context context, AttributeSet attrs) {
		super(context, attrs);

		init();
	}

	public MGridView(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);

		init();
	}

	public void setGridViewAttr(GridViewAttr gridViewAttr, 
			ViewWithShadowAttr itemViewAttr) {
		Log.v("xlh*MGridView*setGridViewAttr", "itemViewAttr="+itemViewAttr);
		mAttrGroup = gridViewAttr;
		mAttrItem = itemViewAttr;
		
		onAttachItemView();
	}
	
	@Override
	public void setSelected(int index) {
		
		Log.v("xlh*MGridView*setSelected", "mFocused="+index+"/mAdapterCount="+mAdapter.getCount());
		mFocused = mSelected = index;

		if (mGainedSize && null!=mAdapter && index<mAdapter.getCount() && null!=mAttrGroup && null!=mAttrItem) {
			mViewNormalContent.removeAllViews();
			mViewFocusedContent.removeAllViews();

			int count = mAdapter.getCount();
			
			// 计算 mContentHeight
			int rows = count / mAttrGroup.columns;
			
			if (0 != count%mAttrGroup.columns) {
				++rows;
			}
			
			mContentHeight = mAttrGroup.paddingTop +rows*(mAttrItem.height+mAttrGroup.rowGap)-mAttrGroup.rowGap+mAttrGroup.paddingBottom;
			// 完成计算 mContentHeight
			
			LayoutParams itemParams = getItemViewLayoutParams(mFocused, mAttrGroup, mAttrItem);
			
//			LayoutParams currentContentLayoutParams = (LayoutParams) mViewContent.getMLayoutParams();
//			int prevContentOffsetY = currentContentLayoutParams.y;
			mContentOffsetY = ensureOffset(itemParams, mAttrItem, mContentOffsetY, 
					true, mContentHeight, mCurrentHeight, mAttrGroup);
			
//			if (prevContentOffsetY != mContentOffsetY) {
//				Anim.trans(mViewContent, 0, mContentOffsetY);
//			}
			
			// 设置 mViewContent
			mViewContent.setMLayoutParams(new LayoutParams(mCurrentWidth, mContentHeight, 0, mContentOffsetY));

			// 添加 itemView
			addItemView(mContentOffsetY);
		}
	}
	
//	绘制items view
	@Override
	protected void onAttachItemView() {
		Log.v("xlh*MGridView*onAttachItemView", "mAdapterCount="+mAdapter.getCount());
		if (mGainedSize && null!=mAdapter && 0<mAdapter.getCount()
				&& null!=mAttrGroup && null!=mAttrItem) {
			if (INVALIDATE_INDEX!=mFocused && mFocused<mAdapter.getCount()) {
			} else {
				mFocused = mSelected = 0;
			}

			int count = mAdapter.getCount();
			
			// 计算 mContentHeight
			int rows = count / mAttrGroup.columns;
			
			if (0 != count%mAttrGroup.columns) {
				++rows;
			}
			
			mContentHeight = mAttrGroup.paddingTop+rows*(mAttrItem.height+mAttrGroup.rowGap)-mAttrGroup.rowGap+mAttrGroup.paddingBottom;
			// 完成计算 mContentHeight
			
			// 设置 mViewContent
//			mViewContent.setMLayoutParams(new LayoutParams(mCurrentWidth, mContentHeight, 0, 0));
			
			LayoutParams itemParams = getItemViewLayoutParams(mFocused, mAttrGroup, mAttrItem);
			
//			LayoutParams currentContentLayoutParams = (LayoutParams) mViewContent.getMLayoutParams();
//			int prevContentOffsetY = currentContentLayoutParams.y;
			mContentOffsetY = ensureOffset(itemParams, mAttrItem, mContentOffsetY, 
					true, mContentHeight, mCurrentHeight, mAttrGroup);
			
//			if (prevContentOffsetY != mContentOffsetY) {
//				Anim.trans(mViewContent, 0, mContentOffsetY);
//			}
			
			// 设置 mViewContent:GridView容器
			mViewContent.setMLayoutParams(new LayoutParams(mCurrentWidth, mContentHeight, 0, mContentOffsetY));

			// 添加 itemView
			addItemView(mContentOffsetY);
		}
	}
	
//	
	@Override
	protected void onAttachFocusView() {
		Log.v("xlh*MGridView*onAttachFocusView", "mAdapterCount="+mAdapter.getCount());
		if (mGainedSize && null!=mViewFocus && null!=mAttrFocus
				&& null!=mAdapter && 0<mAdapter.getCount()
				&& null!=mAttrGroup && null!=mAttrItem) {
			if (mGlobalFocus) {
				if (hasMFocus()) {
					animFocusView(mViewFocus, getFocusViewLayoutParams(
							getItemViewLayoutParams(mFocused, 
									mAttrGroup, mAttrItem), 
							mAttrGroup, mAttrItem, mAttrFocus, 
							mGlobalFocus, mOffsetX, mOffsetY, mContentOffsetY), 
							true);
				}
			} else {
				addIView(mViewFocus, getFocusViewLayoutParams(
						getItemViewLayoutParams(mFocused, 
								mAttrGroup, mAttrItem), 
						mAttrGroup, mAttrItem, mAttrFocus, 
						mGlobalFocus, mOffsetX, mOffsetY, mContentOffsetY));
				
				mViewFocus.setVisibility(hasMFocus() ? VISIBLE : INVISIBLE);
			}
		}
	}
	
	@Override
	protected boolean onKeyCode(int action, int keyCode) {
		if (KeyEvent.ACTION_DOWN != action) {
			return false;
		}
//		被选中的索引
		int target = INVALIDATE_INDEX;
		boolean ensureTop = false;

		switch (keyCode) {
		case KeyCode.LEFT :
			if (0 != (mFocused%mAttrGroup.columns)) {
				target = mFocused - 1;
			}

			break;

		case KeyCode.UP :
			if (0 <= (mFocused-mAttrGroup.columns)) {
				target = mFocused - mAttrGroup.columns;
				ensureTop = true;
			}

			break;

		case KeyCode.RIGHT :
			if ((mAttrGroup.columns-1) != (mFocused%mAttrGroup.columns)) {
				target = mFocused + 1;
				target = target<mAdapter.getCount() ? target : INVALIDATE_INDEX;
			}

			break;

		case KeyCode.DOWN :
			if (0 < (mAdapter.getCount()-(mFocused+mAttrGroup.columns))) {
				target = mFocused + mAttrGroup.columns;
			}
			
			break;
		}
		
		Log.v("xlh*MGridView*onKeyCode", "target="+target);
		if (INVALIDATE_INDEX != target) {
			if (System.currentTimeMillis()-lastTime < Anim.DURATION) {
				return false;
			}

			lastTime = System.currentTimeMillis();
			IView itemView = mRecycler.getUsing(mFocused);
			if (null != itemView) {
				LayoutParams prevParams = (LayoutParams) itemView.getMLayoutParams();
				mViewNormalContent.removeIView(itemView);
				mViewFocusedContent.removeIView(itemView);
				mViewNormalContent.addIView(itemView, prevParams);
				focusItem(itemView, false);
				Anim.scaleNormal(itemView);
			}

			itemView = mRecycler.getUsing(target);
			if (null != itemView) {
				mTargetFocus = INVALIDATE_INDEX;
				LayoutParams prevParams = (LayoutParams) itemView.getMLayoutParams();
				mViewNormalContent.removeIView(itemView);
				mViewFocusedContent.removeIView(itemView);
				mViewFocusedContent.addIView(itemView, prevParams);
				focusItem(itemView, true);
			} else {
				mTargetFocus = target;
			}
			
			mFocused = target;
			LayoutParams itemParams = getItemViewLayoutParams(mFocused, 
					mAttrGroup, mAttrItem);
			
			LayoutParams currentContentLayoutParams = (LayoutParams) mViewContent.getMLayoutParams();
			int prevContentOffsetY = currentContentLayoutParams.y;
			mContentOffsetY = ensureOffset(itemParams, mAttrItem, mContentOffsetY, 
					ensureTop, mContentHeight, mCurrentHeight, mAttrGroup);
			
			if (prevContentOffsetY != mContentOffsetY) {
				Anim.trans(mViewContent, 0, mContentOffsetY);
			}

			LayoutParams focusParams = getFocusViewLayoutParams(
					itemParams, 
					mAttrGroup, mAttrItem, mAttrFocus, 
					mGlobalFocus, mOffsetX, mOffsetY, mContentOffsetY);
//			聚焦动画
			animFocusView(mViewFocus, focusParams, false);
		}
		
		return false;
	}
	
	@Override
	protected void animFocusView(IView view, LayoutParams params, boolean scaled) {
		if (scaled) {
			Anim.transAndScale(view, params);
		} else {
			Anim.trans(view, params);
		}
	}

	@Override
	protected IView getFocusedItemView() {
		return mRecycler.getUsing(mFocused);
	}
	
	protected void addItemView(int offsetY) {
		int start = getFirstIndex(offsetY, mAttrGroup, mAttrItem);
		int end = getLastIndex(offsetY, mCurrentHeight, mAttrGroup, mAttrItem);
		
		start = 0<=start ? start : 0;
		end = end<mAdapter.getCount() ? end : mAdapter.getCount();
		IView itemView;
		
		for (int i=start; i<end; ++i) {
			if (mRecycler.isUsing(i)) {
				continue;
			}

			itemView = mAdapter.getView(i, mRecycler.getFree());
			mRecycler.putUsing(i, itemView);
			
			if (i == mTargetFocus) {
				mViewFocusedContent.addIView(itemView, 
						getItemViewLayoutParams(i, mAttrGroup, mAttrItem));
				mTargetFocus = INVALIDATE_INDEX;
				focusItem(itemView, true);
			} else {
				mViewNormalContent.addIView(itemView, 
						getItemViewLayoutParams(i, mAttrGroup, mAttrItem));
			}
		}
	}
	

	protected void focusItem(IView view, boolean focused) {
		if (focused) {
			Anim.scaleFocused(view, 
					Util.convertIn(mAttrItem.paddingLeft+mAttrItem.scalePrivotX), 
					Util.convertIn(mAttrItem.paddingTop+mAttrItem.scalePrivotY));
		} else {
			Anim.scaleNormal(view);
		}
	}
	
	protected void removeItemView(int offsetY) {
		int start = getFirstIndex(offsetY, mAttrGroup, mAttrItem);
		int end = getLastIndex(offsetY, mCurrentHeight, mAttrGroup, mAttrItem);
		
		start = 0<=start ? start : 0;
		int count = mAdapter.getCount();
		end = end<count ? end : count;
		IView itemView;
		
		for (int i=0; i<start; ++i) {
			if (mRecycler.isUsing(i)) {
				mViewNormalContent.removeIView(mRecycler.getUsing(i));
				mViewFocusedContent.removeIView(mRecycler.getUsing(i));
				mRecycler.changeFree(i);
			}
		}
		
		for (int i=end; i<count; ++i) {
			if (mRecycler.isUsing(i)) {
				mViewNormalContent.removeIView(mRecycler.getUsing(i));
				mViewFocusedContent.removeIView(mRecycler.getUsing(i));
				mRecycler.changeFree(i);
			}
		}
	}
	
	private void init() {
		Log.v("xlh*MGridView*init", "init");
		mViewContent.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
//			布局边界发生变化时候触发 xlh
			@Override
			public void onLayoutChange(View v, int left, int top, int right,
					int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
				
				Log.v("xlh*MGridView*onLayoutChange", "left="+left+"/top="+top+"/right="+right+"/bottom="+bottom);
				int offsetY = Util.convertOut(top);
				removeItemView(offsetY);
				addItemView(offsetY);
			}
		});
	}
	
	/**
	 * 获取聚焦效果的 LayoutParams
	 * @param itemParams
	 * @param gridAttr
	 * @param itemAttr
	 * @param focusAttr
	 * @param global
	 * @param offsetX
	 * @param offsetY
	 * @param contentOffsetY
	 * @return
	 */
	private static LayoutParams getFocusViewLayoutParams(LayoutParams itemParams, 
			GridViewAttr gridAttr, ViewWithShadowAttr itemAttr, 
			ViewWithShadowAttr focusAttr, 
			boolean global, int offsetX, int offsetY, int contentOffsetY) {
		LayoutParams rslt = new LayoutParams(itemParams.width, itemParams.height, 
				itemParams.x, itemParams.y);
		if (itemAttr.hasFocusedScale) {
			rslt.width = (int) (itemAttr.width*itemAttr.scaleX 
					+ focusAttr.paddingLeft + focusAttr.paddingRight) 
					+ 0;
			rslt.height = (int) (itemAttr.height*itemAttr.scaleY 
					+ focusAttr.paddingTop + focusAttr.paddingBottom) 
					+ 0;
			rslt.x = (int) (rslt.x 
					+ (itemAttr.paddingLeft*itemAttr.scaleX - focusAttr.paddingLeft) 
					- (itemAttr.scalePrivotX+itemAttr.paddingLeft)*(itemAttr.scaleX-1) 
					- 0);
			rslt.y = (int) (rslt.y 
					+ (itemAttr.paddingTop*itemAttr.scaleY - focusAttr.paddingTop) 
					- (itemAttr.scalePrivotY+itemAttr.paddingTop)*(itemAttr.scaleY-1) 
					- 0);
		} else {
			rslt.width = itemAttr.width + focusAttr.paddingLeft + focusAttr.paddingRight;
			rslt.height = itemAttr.height + focusAttr.paddingTop + focusAttr.paddingBottom;
			rslt.x += (itemAttr.paddingLeft - focusAttr.paddingLeft);
			rslt.y += (itemAttr.paddingTop - focusAttr.paddingTop);
		}
		
		if (global) {
			rslt.x += offsetX;
			rslt.y += offsetY + contentOffsetY;
		}

		return rslt;
	}

	/**
	 * 获取 item 的LayoutParams
	 * @param index
	 * @param gridAttr
	 * @param itemAttr
	 * @return
	 */
	private static LayoutParams getItemViewLayoutParams( int index, 
			GridViewAttr gridAttr, ViewWithShadowAttr itemAttr) {
		int width = itemAttr.width + itemAttr.paddingLeft + itemAttr.paddingRight;
		int height = itemAttr.height + itemAttr.paddingTop + itemAttr.paddingBottom;

		int row = index / gridAttr.columns;
		int column = index % gridAttr.columns;
		
		int x = gridAttr.paddingLeft 
				+ column*(itemAttr.width+gridAttr.columnGap)
				- itemAttr.paddingLeft;
		
		int y = gridAttr.paddingTop 
				+ row*(itemAttr.height+gridAttr.rowGap)
				- itemAttr.paddingTop;
		
		LayoutParams rslt = new LayoutParams(width, height, x, y);

		return rslt;
	}
	
	private static int ensureOffset(LayoutParams itemParams, ViewWithShadowAttr itemAttr,int offset, boolean ensureTop, int panelHeight, 
			int viewportHeight, GridViewAttr gridAttr) {
		int top = itemParams.y + itemAttr.paddingTop;
		int bottom = top + itemAttr.height;
		int rslt;
		
		if (ensureTop) {
			if (viewportHeight-gridAttr.paddingBottom < bottom+offset) {
				offset = viewportHeight-gridAttr.paddingBottom-bottom;
			}

			if (gridAttr.paddingTop <= (top+offset)) {
				rslt = offset;
			} else {
				rslt = gridAttr.paddingTop - top;
			}
		} else {
			if (top+offset < gridAttr.paddingTop) {
				offset = gridAttr.paddingTop - top;
			}

			if ((bottom+offset) <= (viewportHeight-gridAttr.paddingBottom)) {
				rslt = offset;
			} else {
				rslt = viewportHeight - gridAttr.paddingBottom - bottom;
			}
		}
		
		if (panelHeight+rslt < viewportHeight) {
			rslt = viewportHeight - panelHeight;
		}
		
		if (0 < rslt) {
			rslt = 0;
		}
		
		return rslt;
	}
	
	
	private static int getFirstIndex(int offset, 
			GridViewAttr gridAttr, ViewWithShadowAttr itemAttr) {
		int row = 
		(-offset - itemAttr.height - itemAttr.paddingBottom - gridAttr.paddingTop)
		/(itemAttr.height+gridAttr.rowGap);

		return row*gridAttr.columns;
	}
	
	private static int getLastIndex(int offset, int contentHeight, 
			GridViewAttr gridAttr, ViewWithShadowAttr itemAttr) {
		int row = 
		(-offset + contentHeight + itemAttr.paddingTop - gridAttr.paddingTop)
		/(itemAttr.height+gridAttr.rowGap);
		
		return (row+1)*gridAttr.columns;
	}

}
